home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / arcers / unzip51.zip / AMIGA / AMIGA.C next >
C/C++ Source or Header  |  1994-01-08  |  24KB  |  682 lines

  1. /*------------------------------------------------------------------------
  2.  
  3.   amiga.c
  4.  
  5.   Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.  
  7.   Contents:   mapattr()
  8.               mapname()
  9.               do_wild()
  10.               checkdir()
  11.               cmptime()
  12.               invlocal()
  13.               close_outfile()
  14.  
  15.   History:
  16.      Sep ?? 1992:  Greg Roelofs, original coding (I did??).
  17.      Oct 30 1992:  John Bush, merged FileDate() code with Zip 1.9h.
  18.                    Incorporated Zip's invlocal() routine and omitted 
  19.                    intermediate redundant date format changes.
  20.      Feb 6, 1993:  Separated filedate.c so it could be loaded in Zip too.
  21.      Jul 11 1993:  Added 5.1e routines required.
  22.      Nov 1, 1993:  Compatibilized to 5.1h (JB)
  23.  
  24.   ------------------------------------------------------------------------*/
  25.  
  26.  
  27. #include "unzip.h"
  28.  
  29. /* Globular varibundus */
  30.  
  31. static int created_dir;      /* used in mapname(), checkdir() */
  32. static int renamed_fullpath; /* ditto */
  33. #define PERMS   0777
  34. #define MKDIR(path,mode) mkdir(path)
  35.  
  36.  
  37. #ifndef S_ISCRIPT          /* not having one implies you have none */
  38. #  define S_IARCHIVE 0020  /* not modified since this bit was last set */
  39. #  define S_IREAD    0010  /* can be opened for reading */
  40. #  define S_IWRITE   0004  /* can be opened for writing */
  41. #  define S_IDELETE  0001  /* can be deleted */
  42. #endif /* S_ISCRIPT */
  43.  
  44. #ifndef S_IRWD
  45. #  define S_IRWD     0015  /* useful combo of Amiga privileges */
  46. #endif /* !S_IRWD */
  47.  
  48. #ifndef S_IHIDDEN
  49. #  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS 3.x */
  50. #endif /* !S_HIDDEN */
  51.  
  52.  
  53.  
  54. /**********************/
  55. /* Function mapattr() */
  56. /**********************/
  57.  
  58. int mapattr(void)      /* Amiga version */
  59. {
  60.     ulg  tmp = crec.external_file_attributes;
  61.  
  62.  
  63.     /* Amiga attributes = hsparwed = hidden, script, pure, archive,
  64.      * read, write, execute, delete */
  65.  
  66.     switch (pInfo->hostnum) {
  67.         case AMIGA_:
  68.             if ((tmp & 1) == (tmp>>18 & 1))
  69.                 tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
  70.             /* turn off archive bit for restored Amiga files */
  71.             pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
  72.             break;
  73.  
  74.         case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
  75.         case VMS_:    /* user, group, and other; if writable, set delete bit */
  76.             tmp >>= 16;
  77.             tmp = (( tmp>>6 | tmp>>3 | tmp) & 07) << 1;
  78.             pInfo->file_attr = (unsigned)(tmp&S_IWRITE? tmp|S_IDELETE : tmp);
  79.             break;
  80.  
  81.         /* all other platforms:  assume read-only bit in DOS half of attribute
  82.          * word is set correctly ==> will become READ or READ+WRITE+DELETE */
  83.         case FS_FAT_:
  84.         case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
  85.         case FS_NTFS_:
  86.         case MAC_:
  87.         case ATARI_:
  88.         case TOPS20_:
  89.         default:
  90.             pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD); 
  91.             break;
  92.  
  93.     } /* end switch (host-OS-created-by) */
  94.  
  95.     pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
  96.     return 0;
  97.  
  98. } /* end function mapattr() */
  99.  
  100.  
  101.  
  102.  
  103. /************************/
  104. /*  Function mapname()  */
  105. /************************/
  106.  
  107. int mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  108.     int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  109. {                     /* 3 if error (skip file), 10 if no memory (skip file) */
  110.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  111.     char *pp, *cp=NULL;         /* character pointers */
  112.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  113.     int quote = FALSE;          /* flags */
  114.     int error = 0;
  115.     register unsigned workch;   /* hold the character being tested */
  116.  
  117.  
  118. /*---------------------------------------------------------------------------
  119.     Initialize various pointers and counters and stuff.
  120.   ---------------------------------------------------------------------------*/
  121.  
  122.     /* can create path as long as not just freshening, or if user told us */
  123.     create_dirs = (!fflag || renamed);
  124.  
  125.     created_dir = FALSE;        /* not yet */
  126.  
  127.     /* user gave full pathname:  don't prepend rootpath */
  128.     renamed_fullpath = (renamed && strchr(filename, ':'));
  129.  
  130.     if (checkdir((char *)NULL, INIT) == 10)
  131.         return 10;              /* initialize path buffer, unless no memory */
  132.  
  133.     *pathcomp = '\0';           /* initialize translation buffer */
  134.     pp = pathcomp;              /* point to translation buffer */
  135.     if (jflag)                  /* junking directories */
  136.         cp = (char *)strrchr(filename, '/');
  137.     if (cp == NULL)             /* no '/' or not junking dirs */
  138.         cp = filename;          /* point to internal zipfile-member pathname */
  139.     else
  140.         ++cp;                   /* point to start of last component of path */
  141.  
  142. /*---------------------------------------------------------------------------
  143.     Begin main loop through characters in filename.
  144.   ---------------------------------------------------------------------------*/
  145.  
  146.     while ((workch = (uch)*cp++) != 0) {
  147.  
  148.         if (quote) {                 /* if character quoted, */
  149.             *pp++ = (char)workch;    /*  include it literally */
  150.             quote = FALSE;
  151.         } else
  152.             switch (workch) {
  153.             case '/':             /* can assume -j flag not given */
  154.                 *pp = '\0';
  155.                 if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  156.                     return error;
  157.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  158.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  159.                 break;
  160.  
  161.             case ';':             /* VMS version (or DEC-20 attrib?) */
  162.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  163.                 *pp++ = (char)workch;  /*  later, if requested */
  164.                 break;
  165.  
  166.             case '\026':          /* control-V quote for special chars */
  167.                 quote = TRUE;     /* set flag for next character */
  168.                 break;
  169.  
  170.             default:
  171.                 /* allow European characters in filenames: */
  172.                 if (isprint(workch) || (128 <= workch && workch <= 255))
  173.                     *pp++ = (char)workch;
  174.             } /* end switch */
  175.  
  176.     } /* end while loop */
  177.  
  178.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  179.  
  180.     /* if not saving them, remove with VMS version numbers (appended ";###") */
  181.     if (!V_flag && lastsemi) {
  182.         pp = lastsemi + 1;
  183.         while (isdigit((uch)(*pp)))
  184.             ++pp;
  185.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  186.             *lastsemi = '\0';
  187.     }
  188.  
  189. /*---------------------------------------------------------------------------
  190.     Report if directory was created (and no file to create:  filename ended
  191.     in '/'), check name to be sure it exists, and combine path and name be-
  192.     fore exiting.
  193.   ---------------------------------------------------------------------------*/
  194.  
  195.     if (filename[strlen(filename) - 1] == '/') {
  196.         if (checkdir(filename, GETPATH) == 1) {
  197.             fprintf(stderr, "pathname too long:  truncat{ed/ing}\n");
  198.             return 1;  /* GRR:  NEEDS WORK! (do checking only when appending) */
  199.         }
  200.         if (created_dir && QCOND2) {
  201.             fprintf(stdout, "   creating: %s\n", filename);
  202.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  203.         }
  204.         return 2;   /* dir existed already; don't look for data to extract */
  205.     }
  206.  
  207.     if (*pathcomp == '\0') {
  208.         fprintf(stderr, "mapname:  conversion of %s failed\n", filename);
  209.         return 3;
  210.     }
  211.  
  212.     if ((error = checkdir(pathcomp, APPEND_NAME)) == 1) {
  213.         /* GRR:  OK if truncated here:  warn and continue */
  214.         /* (warn in checkdir?) */
  215.     }
  216.     checkdir(filename, GETPATH);
  217.  
  218.     return error;
  219.  
  220. } /* end function mapname() */
  221.  
  222.  
  223. static int ispattern(char *p)
  224. {
  225.     register char c;
  226.     while (c = *p++)
  227.     if (c == '\\') {
  228.         if (!*++p)
  229.         return FALSE;
  230.         } else if (c == '?' || c == '*')
  231.             return TRUE;
  232.         else if (c == '[') {
  233.             for (;;) {
  234.                 if (!(c = *p++))
  235.                     return FALSE;
  236.                 else if (c == '\\') {
  237.                     if (!*++p)
  238.             return FALSE;
  239.                 } else if (c == ']')
  240.                     return TRUE;
  241.             }
  242.         }
  243.     return FALSE;
  244. }
  245.  
  246. /**********************/
  247. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  248. /**********************/
  249.  
  250. char *do_wild(wildspec)
  251.     char *wildspec;         /* only used first time on a given dir */
  252. {
  253.     static DIR *dir = NULL;
  254.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  255.     static int firstcall=TRUE, have_dirname, dirnamelen;
  256.     struct dirent *file;
  257.     BPTR lok = 0;
  258.     /* Even when we're just returning wildspec, we *always* do so in
  259.      * matchname[]--calling routine is allowed to append four characters
  260.      * to the returned string, and wildspec may be a pointer to argv[].
  261.      */
  262.     if (firstcall) {        /* first call:  must initialize everything */
  263.         firstcall = FALSE;
  264.         /* avoid needless readdir() scans: */
  265.         if (!ispattern(wildspec) || (lok = Lock(wildspec, ACCESS_READ))) {
  266.             if (lok) UnLock(lok);
  267.             have_dirname = FALSE;
  268.             strcpy(matchname, wildspec);
  269.             return matchname;
  270.         }
  271.  
  272.         /* break the wildspec into a directory part and a wildcard filename */
  273.         if ((wildname = strrchr(wildspec, '/')) == NULL
  274.                         && (wildname = strrchr(wildspec, ':')) == NULL) {
  275.             dirname = "";               /* current dir */
  276.             dirnamelen = 1;
  277.             have_dirname = FALSE;
  278.             wildname = wildspec;
  279.         } else {
  280.             ++wildname;     /* point at character after '/' or ':' */
  281.             dirnamelen = wildname - wildspec;
  282.             if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  283.                 fprintf(stderr, "warning:  can't allocate wildcard buffers\n");
  284.                 strcpy(matchname, wildspec);
  285.                 return matchname;   /* but maybe filespec was not a wildcard */
  286.             }
  287.             strncpy(dirname, wildspec, dirnamelen);
  288.             dirname[dirnamelen] = 0;
  289.             have_dirname = TRUE;
  290.         }
  291.  
  292.         if ((dir = opendir(dirname)) != NULL) {
  293.             while ((file = readdir(dir)) != NULL) {
  294.                 if (match(file->d_name, wildname, 1)) {  /* case insensitive */
  295.                     if (have_dirname) {
  296.                         strcpy(matchname, dirname);
  297.                         strcpy(matchname+dirnamelen, file->d_name);
  298.                     } else
  299.                         strcpy(matchname, file->d_name);
  300.                     return matchname;
  301.                 }
  302.             }
  303.             /* if we get to here directory is exhausted, so close it */
  304.             closedir(dir);
  305.             dir = NULL;
  306.         }
  307.  
  308.         /* return the raw wildspec in case that works (e.g., directory not
  309.          * searchable, but filespec was not wild and file is readable) */
  310.         strcpy(matchname, wildspec);
  311.         return matchname;
  312.     }
  313.  
  314.     /* last time through, might have failed opendir but returned raw wildspec */
  315.     if (dir == NULL) {
  316.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  317.         if (have_dirname)
  318.             free(dirname);
  319.         return (char *)NULL;
  320.     }
  321.  
  322.     /* If we've gotten this far, we've read and matched at least one entry
  323.      * successfully (in a previous call), so dirname has been copied into
  324.      * matchname already.
  325.      */
  326.     while ((file = readdir(dir)) != NULL)
  327.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  328.             if (have_dirname) {
  329.                 /* strcpy(matchname, dirname); */
  330.                 strcpy(matchname+dirnamelen, file->d_name);
  331.             } else
  332.                 strcpy(matchname, file->d_name);
  333.             return matchname;
  334.         }
  335.  
  336.     closedir(dir);     /* have read at least one dir entry; nothing left */
  337.     dir = NULL;
  338.     firstcall = TRUE;  /* reset for new wildspec */
  339.     if (have_dirname)
  340.         free(dirname);
  341.     return (char *)NULL;
  342.  
  343. } /* end function do_wild() */
  344.  
  345.  
  346.  
  347. /***********************/
  348. /* Function checkdir() */
  349. /***********************/
  350.  
  351. int checkdir(pathcomp, flag)
  352.     char *pathcomp;
  353.     int flag;
  354. /*
  355.  * returns:  1 - (on APPEND_xxx) truncated path component
  356.  *           2 - path doesn't exist, not allowed to create
  357.  *           3 - path doesn't exist, tried to create and failed; or
  358.  *               path exists and is not a directory, but is supposed to be
  359.  *          10 - can't allocate memory for filename buffers
  360.  */
  361. {
  362.     static int rootlen = 0;   /* length of rootpath */
  363.     static char *rootpath;    /* user's "extract-to" directory */
  364.     static char *buildpath;   /* full path (so far) to extracted file */
  365.     static char *end;         /* pointer to end of buildpath ('\0') */
  366.  
  367. #   define FN_MASK   7
  368. #   define FUNCTION  (flag & FN_MASK)
  369.  
  370.  
  371.  
  372. /*---------------------------------------------------------------------------
  373.     APPEND_DIR:  append the path component to the path being built and check
  374.     for its existence.  If doesn't exist and we are creating directories, do
  375.     so for this one; else signal success or error as appropriate.
  376.   ---------------------------------------------------------------------------*/
  377.  
  378. /* GRR:  check path length after each segment:  warn about truncation */
  379.  
  380.     if (FUNCTION == APPEND_DIR) {
  381.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  382.         while ((*end = *pathcomp++))
  383.             ++end;
  384.         if (stat(buildpath, &statbuf)) {   /* path doesn't exist */
  385.             if (!create_dirs) {   /* told not to create (freshening) */
  386.                 free(buildpath);
  387.                 return 2;         /* path doesn't exist:  nothing to do */
  388.             }
  389.             if (MKDIR(buildpath, 0777) == -1) {   /* create the directory */
  390.                 fprintf(stderr, 
  391.                 "checkdir:  can't create %s\n           unable to process %s.\n"
  392.                   , buildpath, filename);
  393.                 fflush(stderr);
  394.                 free(buildpath);
  395.                 return 3;      /* path didn't exist, tried to create, failed */
  396.             }
  397.             created_dir = TRUE;
  398.         } else if (!S_ISDIR(statbuf.st_mode)) {
  399.             fprintf(stderr, "checkdir:  %s exists but is not a directory\n\
  400.            unable to process %s.\n", buildpath, filename);
  401.             fflush(stderr);
  402.             free(buildpath);
  403.             return 3;          /* path existed but wasn't dir */
  404.         }
  405.         *end++ = '/';
  406.         *end = '\0';
  407.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  408.         return 0;
  409.  
  410.     } /* end if (FUNCTION == APPEND_DIR) */
  411.  
  412. /*---------------------------------------------------------------------------
  413.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  414.     buildpath.
  415.   ---------------------------------------------------------------------------*/
  416.  
  417.     if (FUNCTION == GETPATH) {
  418.         strcpy(pathcomp, buildpath);  /* DO ERROR CHECKING:  TOO LONG? */
  419.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  420.         free(buildpath);
  421.         buildpath = end = NULL;
  422.         return 0;
  423.     }
  424.  
  425. /*---------------------------------------------------------------------------
  426.     APPEND_NAME:  assume the path component is the filename; append it and
  427.     return without checking for existence.
  428.   ---------------------------------------------------------------------------*/
  429.  
  430.     if (FUNCTION == APPEND_NAME) {                /* DO ERROR CHECKING */
  431.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  432.         while ((*end = *pathcomp++))
  433.             ++end;
  434.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  435.         return 0;  /* could check for existence here, prompt for new name... */
  436.     }
  437.  
  438. /*---------------------------------------------------------------------------
  439.     INIT:  allocate and initialize buffer space for the file currently being
  440.     extracted.  If file was renamed with an absolute path, don't prepend the
  441.     extract-to path.
  442.   ---------------------------------------------------------------------------*/
  443.  
  444.     if (FUNCTION == INIT) {
  445.         Trace((stderr, "initializing buildpath to "));
  446.         if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) == NULL)
  447.             return 10;
  448.         if ((rootlen > 0) && !renamed_fullpath) {
  449.             strcpy(buildpath, rootpath);
  450.             end = buildpath + rootlen;
  451.         } else {
  452.             *buildpath = '\0';
  453.             end = buildpath;
  454.         }
  455.         Trace((stderr, "[%s]\n", buildpath));
  456.         return 0;
  457.     }
  458.  
  459. /*---------------------------------------------------------------------------
  460.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  461.     sary; else assume it's a zipfile member and return.  This path segment
  462.     gets used in extracting all members from every zipfile specified on the
  463.     command line.
  464.   ---------------------------------------------------------------------------*/
  465.  
  466.     if (FUNCTION == ROOT) {
  467.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  468.         if (pathcomp == NULL) {
  469.             rootlen = 0;
  470.             return 0;
  471.         }
  472.         if ((rootlen = strlen(pathcomp)) > 0) {
  473.             int had_trailing_pathsep=FALSE;
  474.  
  475.             if (pathcomp[rootlen-1] == '/') {
  476.                 pathcomp[--rootlen] = '\0';
  477.                 had_trailing_pathsep = TRUE;
  478.             }
  479.             if (stat(pathcomp, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
  480.                 /* path does not exist */
  481.                 if (!create_dirs || !had_trailing_pathsep) {
  482.                     rootlen = 0;
  483.                     return 2;   /* treat as stored file */
  484.                 }
  485. /* GRR:  scan for wildcard characters?  OS-dependent...  if find any, return 2:
  486.  * treat as stored file(s) */
  487.                 /* create the directory (could add loop here to scan pathcomp
  488.                  * and create more than one level, but why really necessary?) */
  489.                 if (MKDIR(pathcomp, 0777) == -1) {
  490.                     fprintf(stderr,
  491.                       "checkdir:  can't create extraction directory: %s\n",
  492.                       pathcomp);
  493.                     fflush(stderr);
  494.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  495.                     return 3;  /* failed:  file exists, or 2+ levels required */
  496.                 }
  497.             }
  498.             if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  499.                 rootlen = 0;
  500.                 return 10;
  501.             }
  502.             strcpy(rootpath, pathcomp);
  503.             if (rootpath[rootlen - 1] != ':')
  504.                 rootpath[rootlen++] = '/';
  505.             rootpath[rootlen] = '\0';
  506.         }
  507.         Trace((stderr, "rootpath now = [%s]\n", rootpath));
  508.         return 0;
  509.     }
  510.  
  511. /*---------------------------------------------------------------------------
  512.     END:  free rootpath, immediately prior to program exit.
  513.   ---------------------------------------------------------------------------*/
  514.  
  515.     if (FUNCTION == END) {
  516.         Trace((stderr, "freeing rootpath\n"));
  517.         if (rootlen > 0)
  518.             free(rootpath);
  519.         return 0;
  520.     }
  521.  
  522.     return 99;  /* should never reach */
  523.  
  524. } /* end function checkdir() */
  525.  
  526.  
  527. /**********************/
  528. /* Function cmptime() */
  529. /**********************/
  530.  
  531. /* cmptime() clone pinched from from Zip1.9h,
  532.  * by Mark Adler, Jean-loup Gailly, et al., circa 1991.  
  533.  * Incorporated into UnZip 5.1d by John Bush
  534.  */
  535.  
  536. int cmptime(p, q)
  537. struct tm *p, *q;       /* times to compare */
  538. /* Return negative if time p is before time q, positive if after, and
  539.    zero if the same */
  540. {
  541.   int r;                /* temporary variable */
  542.  
  543.   if (p == NULL)
  544.     return -1;
  545.   else if ((r = p->tm_year - q->tm_year) != 0)
  546.     return r;
  547.   else if ((r = p->tm_mon - q->tm_mon) != 0)
  548.     return r;
  549.   else if ((r = p->tm_mday - q->tm_mday) != 0)
  550.     return r;
  551.   else if ((r = p->tm_hour - q->tm_hour) != 0)
  552.     return r;
  553.   else if ((r = p->tm_min - q->tm_min) != 0)
  554.     return r;
  555.   else
  556.     return p->tm_sec - q->tm_sec;
  557. }
  558.  
  559.  
  560. /***********************/
  561. /* Function invlocal() */
  562. /***********************/
  563.  
  564. /* mktime() clone pinched from from Zip1.9h,
  565.  * by Mark Adler and Jean-loup Gailly, et.al, circa 1991.  
  566.  * Incorporated into UnZip 5.1d by John Bush
  567.  */
  568. time_t invlocal(t)
  569. struct tm *t;           /* time to convert */
  570. /* Find inverse of localtime() using bisection.  This routine assumes that
  571.    time_t is an integer type, either signed or unsigned.  The expectation
  572.    is that sometime before the year 2038, time_t will be made a 64-bit
  573.    integer, and this routine will still work. */
  574. {
  575.   time_t i;             /* midpoint of current root range */
  576.   time_t l;             /* lower end of root range */
  577.   time_t u;             /* upper end of root range */
  578.  
  579.   /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  580.      integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  581.      the Unix systems in the world come to a grinding halt.  Either that, or
  582.      all those systems will suddenly find themselves transported to December
  583.      of 1901 ... */
  584.   l = 0;
  585.   u = 1;
  586.   while (u < (u << 1))
  587.     u = (u << 1) + 1;
  588.  
  589.   /* Find the root */
  590.   while (u - l > 1)
  591.   {
  592.     i = l + ((u - l) >> 1);
  593.     if (cmptime(localtime(&i), t) <= 0)
  594.       l = i;
  595.     else
  596.       u = i;
  597.   }
  598.   return l;
  599. }
  600.  
  601.  
  602.  
  603. /**************************************/
  604. /* Function close_outfile() */
  605. /**************************************/
  606. /* this part differs slightly with Zip */
  607. /*-------------------------------------*/
  608.  
  609. void close_outfile(void)
  610. {
  611.     struct tm t;                /* good ole time structure */
  612.     time_t u[2];                /* mean ole time stamp */
  613.     ulg dd,dt;                  /* DOS format time stamps */
  614.     LONG FileDate();
  615.     time_t invlocal();
  616.  
  617.     if (cflag)                  /* can't set time on stdout */
  618.         return;
  619.  
  620.   /* close the file *before* setting its time under AmigaDos */
  621.  
  622.     fclose(outfile);
  623.  
  624.   /* assign date and time to local variables */
  625.  
  626.     dd = lrec.last_mod_file_date;
  627.     dt = lrec.last_mod_file_time;
  628.  
  629.   /* Convert DOS time to time_t format in (time_t)u */
  630.  
  631.     t.tm_sec =   (int) (dt <<  1) & 0x3e;
  632.     t.tm_min =   (int) (dt >>  5) & 0x3f;
  633.     t.tm_hour =  (int) (dt >> 11) & 0x1f;
  634.  
  635.     t.tm_mday =  (int) (dd        & 0x1f);
  636.     t.tm_mon =  ((int) (dd >>  5) & 0xf ) - 1;
  637.     t.tm_year = ((int) (dd >>  9) & 0x7f) + 80;
  638.  
  639.   /* invlocal() is equivalent to mktime() */
  640.  
  641.     u[0] = u[1] = invlocal(&t); 
  642.  
  643. #ifdef DEBUG
  644.     fprintf (stderr,"\nclose_outfile(): u=%s\n",ctime(&u[0]));
  645. #endif
  646.  
  647.     if (!FileDate(filename, u))
  648.         fprintf(stderr, "warning:  can't set the time for %s\n", filename);
  649.  
  650.   /* set file perms after closing (not done at creation)--see mapattr() */
  651.  
  652.     chmod(filename, pInfo->file_attr);
  653.  
  654. } /* end function close_outfile() */
  655.  
  656.  
  657. /********************************************************************/
  658. /* Load filedate as a separate external file; it's used by Zip, too.*/
  659. /*                                                                  */
  660. #include "amiga/filedate.c"                                      /* */
  661. /*                                                                  */
  662. /********************************************************************/
  663.  
  664. /**************** for Aztec, do linewise with stat.c ****************/
  665.  
  666. #ifdef AZTEC_C
  667. #  include "amiga/stat.c"
  668. /* this is the exact same stat.c used for Aztec by Zip */
  669.  
  670. #  include <stdio.h>
  671. #  include "crypt.h"
  672.  
  673. void _abort(void)               /* called when ^C is pressed */
  674. {
  675.     echon();
  676.     close_leftover_open_dirs();
  677.     fflush(stdout);
  678.     fputs("\n^C\n", stderr);
  679.     exit(1);
  680. }
  681. #endif /* AZTEC_C */
  682.